package com.quectel.core.module.scheduling.service.impl;


import cn.hutool.core.lang.func.LambdaUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.quectel.constant.global.SystemConstants;
import com.quectel.core.constants.RedisCacheConstants;
import com.quectel.core.module.dept.dto.DeptPersonDto;
import com.quectel.core.module.scheduling.dao.SchedulingAttendanceGroupDao;
import com.quectel.core.module.scheduling.dao.SchedulingAttendanceGroupHeadBindingDao;
import com.quectel.core.module.scheduling.dao.SchedulingAttendanceGroupPersonBindingDao;
import com.quectel.core.module.scheduling.dto.*;
import com.quectel.core.module.scheduling.entity.SchedulingAttendanceGroupEntity;
import com.quectel.core.module.scheduling.entity.SchedulingAttendanceGroupHeadBindingEntity;
import com.quectel.core.module.scheduling.entity.SchedulingAttendanceGroupPersonBindingEntity;
import com.quectel.core.module.scheduling.service.*;
import com.quectel.core.module.village.dto.VillageDto;
import com.quectel.core.module.village.service.VillageService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.kit.CacheKit;
import com.quectel.util.kit.Snowflake;
import com.quectel.util.mybatis.MyBatisPlusUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
/**
 *
 * @author zhangheng
 * @email nolan.zhang@quectel.com
 * @date 2023/07/05 13:24
 */
@DubboService
public class SchedulingAttendanceGroupServiceImpl implements SchedulingAttendanceGroupService{

    private static final Logger LOGGER = LoggerFactory.getLogger(SchedulingAttendanceGroupServiceImpl.class);

    /**
     * 入参解释:实体id
     */
    private static final Function<Long, String> SCHEDULING_ATTENDANCE_GROUP_CACHE_BY_ID_FUNC = id -> String.format(RedisCacheConstants.PROJECT_NAME + "SCHEDULING_ATTENDANCE_GROUP_CACHE_BY_ID:%d", id);

    /**
     * 清除缓存方法
     */
    private static final Consumer<SchedulingAttendanceGroupDto> CLEAR_CACHE_FUNC = dto -> {
        CacheKit.invalidRedisCache(SCHEDULING_ATTENDANCE_GROUP_CACHE_BY_ID_FUNC.apply(dto.getId()));
    };

    @Autowired
    private SchedulingAttendanceGroupDao schedulingAttendanceGroupDao;
    @Autowired
    private VillageService villageService;
    @Autowired
    private SchedulingAttendanceGroupHeadBindingDao headPersonBindingDao;
    @Autowired
    private SchedulingAttendanceGroupHeadBindingService headPersonBindingService;
    @Autowired
    private SchedulingAttendanceGroupPersonBindingService personBindingService;
    @Autowired
    private SchedulingAttendanceGroupPersonBindingDao personBindingDao;
    @Autowired
    private SchedulingCalendarConfigService schedulingCalendarConfigService;
    @Autowired
    private SchedulingWorkOvertimeConfigService workOvertimeConfigService;


    /**
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void saveOrUpdate(SchedulingAttendanceGroupDto dto) {
        if (dto.getId() == null){
            Long id = save(dto);
            dto.setId(id);
        }else {
            updateById(dto);
        }

        // 删除绑定关系1-考勤组负责人
        headPersonBindingDao.delete(new LambdaQueryWrapper<SchedulingAttendanceGroupHeadBindingEntity>()
                .eq(SchedulingAttendanceGroupHeadBindingEntity::getSchedulingAttendanceGroupId,
                        dto.getId()));

        // 绑定下员工信息到考勤组负责人绑定关系中间表
        for (DeptPersonDto personDto : dto.getHeadPersonList()) {
            SchedulingAttendanceGroupHeadBindingDto bindingDto = new SchedulingAttendanceGroupHeadBindingDto();
            bindingDto.setId(Snowflake.nextId());
            bindingDto.setSchedulingAttendanceGroupId(dto.getId());
            bindingDto.setPersonId(personDto.getId());
            headPersonBindingService.save(bindingDto);
        }

        // 删除绑定关系2-考勤组人员
        personBindingDao.delete(new LambdaQueryWrapper<SchedulingAttendanceGroupPersonBindingEntity>()
                .eq(SchedulingAttendanceGroupPersonBindingEntity::getSchedulingAttendanceGroupId,
                        dto.getId()));

        // 绑定下员工信息到考勤组人员绑定关系中间表
        for (DeptPersonDto personDto : dto.getPersonList()) {
            SchedulingAttendanceGroupPersonBindingDto bindingDto = new SchedulingAttendanceGroupPersonBindingDto();
            bindingDto.setId(Snowflake.nextId());
            bindingDto.setSchedulingAttendanceGroupId(dto.getId());
            bindingDto.setPersonId(personDto.getId());
            personBindingService.save(bindingDto);
        }
    }

    @Override
    public SchedulingAttendanceGroupDto selectCacheById(Long id) {
        return CacheKit.cacheToRedis(
                () -> selectById(id),
                SCHEDULING_ATTENDANCE_GROUP_CACHE_BY_ID_FUNC.apply(id),
                SystemConstants.NOT_NULL_CACHE_EXPIRE_SECONDS
        );
    }

    @Override
    public SchedulingAttendanceGroupDto selectById(Long id){
            SchedulingAttendanceGroupEntity entity = schedulingAttendanceGroupDao.selectById(id);
        return paddingField(CopyUtils.copyObj(entity,SchedulingAttendanceGroupDto.class));
    }

    @Override
    public List<SchedulingAttendanceGroupDto> queryList(Map<String,Object> params){
        List<SchedulingAttendanceGroupEntity> list = schedulingAttendanceGroupDao.queryList(params);
        List<SchedulingAttendanceGroupDto> result =  CopyUtils.copyList(list,SchedulingAttendanceGroupDto.class);
        result.forEach(this::paddingField);
        return result;
    }

    @Override
    public List<SchedulingAttendanceGroupDto> queryListWithoutPadding(Map<String,Object> params){
        List<SchedulingAttendanceGroupEntity> list = schedulingAttendanceGroupDao.queryList(params);
        return CopyUtils.copyList(list,SchedulingAttendanceGroupDto.class);
    }

    /**
     * 此方法慎用 禁止填充List一类 比如一个人有多个地址这里不允许填充
     * 填充的原则是: 1:被填充对象不经常变换 2:根据id可以走缓存 3数据足够简单 比如设备类型 所属园区等
     *
     * @param dto
     * @return
     */
    private SchedulingAttendanceGroupDto paddingField(SchedulingAttendanceGroupDto dto){
        if (dto != null){
            if (dto.getVillageId() != null){
                VillageDto villageDto = villageService.selectCacheById(dto.getVillageId());
                if (villageDto != null){
                    dto.setVillageName(villageDto.getName());
                }
            }
            if (dto.getSchedulingCalendarId() != null){
                SchedulingCalendarConfigDto schedulingCalendarConfigDto =
                        schedulingCalendarConfigService.selectCacheById(dto.getSchedulingCalendarId());
                if (schedulingCalendarConfigDto != null){
                    dto.setSchedulingCalendarName(schedulingCalendarConfigDto.getName());
                }
            }

            if (dto.getWorkOvertimeId() != null){
                SchedulingWorkOvertimeConfigDto schedulingWorkOvertimeConfigDto =
                        workOvertimeConfigService.selectCacheById(dto.getWorkOvertimeId());
                if (schedulingWorkOvertimeConfigDto != null){
                    dto.setWorkOvertimeName(schedulingWorkOvertimeConfigDto.getName());
                }
            }

            List<DeptPersonDto> deptPersonDtos = headPersonBindingService.selectPersonByGroupId(dto.getId());
            dto.setHeadPersonList(deptPersonDtos);

            Map<String,Object> personBindMap = new HashMap<>();
            personBindMap.put(LambdaUtil.getFieldName(SchedulingAttendanceGroupPersonBindingDto::getSchedulingAttendanceGroupId),dto.getId());
            int personBindCount = personBindingService.queryTotal(personBindMap);
            dto.setPersonCount(personBindCount);
        }
        return dto;
    }

    @Override
    public int queryTotal(Map<String, Object> params){
        return schedulingAttendanceGroupDao.queryTotal(params);
    }

    @Override
    public Long save(SchedulingAttendanceGroupDto dto){
        SchedulingAttendanceGroupEntity entity = CopyUtils.copyObj(dto,SchedulingAttendanceGroupEntity.class);
        entity.setId(Snowflake.nextId());
        schedulingAttendanceGroupDao.insert(entity);
        return entity.getId();
    }

    @Override
    public void updateById(SchedulingAttendanceGroupDto dto){
        SchedulingAttendanceGroupEntity entity = CopyUtils.copyObj(dto,SchedulingAttendanceGroupEntity.class);

        schedulingAttendanceGroupDao.updateById(entity);

        CLEAR_CACHE_FUNC.accept(dto);
    }

    @Override
    public void updateAllColumnById(SchedulingAttendanceGroupDto dto) {
       SchedulingAttendanceGroupEntity entity = CopyUtils.copyObj(dto,SchedulingAttendanceGroupEntity.class);

       MyBatisPlusUtils.updateAllColumnById(entity, schedulingAttendanceGroupDao);

       CLEAR_CACHE_FUNC.accept(dto);
    }

    @Override
    public void deleteById(Long id){

        CLEAR_CACHE_FUNC.accept(selectById(id));

        schedulingAttendanceGroupDao.deleteById(id);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(Long[] ids){
        for (Long id : ids) {
            deleteById(id);
        }
    }
}
